Lazily load hashes for registry sources
authorAlex Crichton <alex@alexcrichton.com>
Wed, 25 Mar 2015 18:39:47 +0000 (11:39 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 25 Mar 2015 18:39:47 +0000 (11:39 -0700)
The hashes would occasionally disappear when the main package registry overwrote
a previous registry source, so this just adds logic to load hashes if they're
missing.

Closes #1355

src/cargo/core/registry.rs
src/cargo/sources/registry.rs

index adf05b0fad622ee1cabedf66bc39c95ea417a289..54f3ff87ed6cb44ccc573b1ef3f25444eb3d4876 100644 (file)
@@ -110,11 +110,15 @@ impl<'a, 'b> PackageRegistry<'a, 'b> {
             // We've previously loaded this source, and we've already locked it,
             // so we're not allowed to change it even if `namespace` has a
             // slightly different precise version listed.
-            Some(&(_, Kind::Locked)) => return Ok(()),
+            Some(&(_, Kind::Locked)) => {
+                debug!("load/locked   {}", namespace);
+                return Ok(())
+            }
 
             // If the previous source was not a precise source, then we can be
             // sure that it's already been updated if we've already loaded it.
             Some(&(ref previous, _)) if previous.precise().is_none() => {
+                debug!("load/precise  {}", namespace);
                 return Ok(())
             }
 
@@ -123,10 +127,14 @@ impl<'a, 'b> PackageRegistry<'a, 'b> {
             // updating this source.
             Some(&(ref previous, _)) => {
                 if previous.precise() == namespace.precise() {
+                    debug!("load/match    {}", namespace);
                     return Ok(())
                 }
+                debug!("load/mismatch {}", namespace);
+            }
+            None => {
+                debug!("load/missing  {}", namespace);
             }
-            None => {}
         }
 
         try!(self.load(namespace, Kind::Normal));
index cf5db84eaed473478ff95213ee82f0881004e7fb..ad7ed0ba59358d678e420635107ff99c75aeeb76 100644 (file)
@@ -298,13 +298,14 @@ impl<'a, 'b> RegistrySource<'a, 'b> {
     /// No action is taken if the package is already downloaded.
     fn download_package(&mut self, pkg: &PackageId, url: &Url)
                         -> CargoResult<PathBuf> {
-        // TODO: should discover from the S3 redirect
+        // TODO: should discover filename from the S3 redirect
         let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
         let dst = self.cache_path.join(&filename);
         if fs::metadata(&dst).is_ok() { return Ok(dst) }
         try!(self.config.shell().status("Downloading", pkg));
 
         try!(fs::create_dir_all(dst.parent().unwrap()));
+        let expected_hash = try!(self.hash(pkg));
         let handle = match self.handle {
             Some(ref mut handle) => handle,
             None => {
@@ -320,17 +321,12 @@ impl<'a, 'b> RegistrySource<'a, 'b> {
         }
 
         // Verify what we just downloaded
-        let expected = self.hashes.get(&(pkg.name().to_string(),
-                                         pkg.version().to_string()));
-        let expected = try!(expected.chain_error(|| {
-            internal(format!("no hash listed for {}", pkg))
-        }));
         let actual = {
             let mut state = Sha256::new();
             state.update(resp.get_body());
             state.finish()
         };
-        if actual.to_hex() != *expected {
+        if actual.to_hex() != expected_hash {
             return Err(human(format!("Failed to verify the checksum of `{}`",
                                      pkg)))
         }
@@ -339,6 +335,19 @@ impl<'a, 'b> RegistrySource<'a, 'b> {
         Ok(dst)
     }
 
+    /// Return the hash listed for a specified PackageId.
+    fn hash(&mut self, pkg: &PackageId) -> CargoResult<String> {
+        let key = (pkg.name().to_string(), pkg.version().to_string());
+        if let Some(s) = self.hashes.get(&key) {
+            return Ok(s.clone())
+        }
+        // Ok, we're missing the key, so parse the index file to load it.
+        try!(self.summaries(pkg.name()));
+        self.hashes.get(&key).chain_error(|| {
+            internal(format!("no hash listed for {}", pkg))
+        }).map(|s| s.clone())
+    }
+
     /// Unpacks a downloaded package into a location where it's ready to be
     /// compiled.
     ///